export let request = {
	/**
	 * url
	 */
	urlBase: '',
	url: {
		/* 用户 */
		xLoginNormal: '/auth/login',
		xLoginPhoneByPassword: '/auth/password/login', // 手机 密码登录
		xLoginPhoneByVerifyCode: '/auth/sms/login', //手机号验证码登录
		xLoginSendVerifyCode: '/sms/verify-code', // 发送手机验证码
		xLoginPlatformLogin: '/wechat/mini/mobile/oauth', // oauth 登录
		xLoginPartyByWeChat: '/wechat/mix/code/login', // 微信第三方登录接口
		xLoginPartyBindByWeChat: '/wechat/mix/code/login', // 微信第三方登录接口
		xLoginPartyUnbindByWeChat: '/auth/oauth/unbind', //用户解绑
		xLoginPartyByApple: '/auth/apple/oauth', // 苹果第三方登录接口
		xLoginPartyBindByApple: '/auth/apple/oauth', // 微信第三方登录接口
		xLoginPartyUnbindByApple: '/auth/oauth/unbind', //用户解绑
		xLoginGetMemberInfo: '/vip/info', // 会员信息
		xLoginRegister: '/auth/register', // 手机 密码注册
		xLoginRegisterResetPassword: '/auth/password/reset', // 找回密码/重置密码
		
		/* 通用 */
		xRequestUpload: '/file/action-upload', //  上传文件
	},

	/**
	 * upload
	 */
	upload(options={}, arg1, arg2, arg3) {
		// 适配非对象参数
		if(typeof options === 'string') options = {
			url: options,
			// #ifdef H5
			file: arg1,
			// #endif
			// #ifndef H5
			filePath: arg1,
			// #endif
			name: arg2,
			data: arg3
		}
		let requestData = {header: {},data: {}}
		let raw
		let responseData
		let error 

		requestData = request.setRequestUrl(requestData, 'upload', options)
		requestData = request.setRequestMethod(requestData, 'upload', options)
		requestData = request.setRequestHeader(requestData, 'upload', options)
		requestData = request.setRequestData(requestData, 'upload', options)
		requestData = request.setRequestOther(requestData, 'upload', options)
		requestData = request.requestHandle(requestData, 'upload', options)
		if(requestData===false) return Promise.reject()
		request.requestBefore(requestData, 'upload', options)

		// 请求
		console.log('xrequest upload:', requestData)
		return new Promise((resolve, reject)=>{
			const task = uni.uploadFile({
				...requestData,
				success: res=>{
					raw = res
					responseData = res
					console.log('xrequest upload response:', responseData)
					request.requestAfter(error, responseData, requestData, 'upload', options, raw)

					responseData = request.responseHandle(responseData, requestData, 'upload', options, raw)
					if(responseData===false) return reject()

					let code = request.getResponseCode(responseData, requestData, 'upload', options, raw)
					let message = request.getResponseMessage(responseData, requestData, 'upload', options, raw)
					let data = request.getResponseData(responseData, requestData, 'upload', options, res)
					let ret = request.responseCheck(code, message, data, responseData, requestData, 'upload', options, raw)
					console.log('xrequest upload response check:', ret)
					responseData = ret.data

					if(ret.isClear) uni.$x.auth.logouted(true)
					if(ret.isGoLogin) setTimeout(uni.$x.navigator.goLogin(), 500)
					error = ret.error
					if(error) reject(request.failHandle(error, responseData, requestData, 'upload', options, raw))
					if(!error) resolve(request.successHandle(responseData, requestData, 'upload', options, raw))
				},
				fail: err=>{
					request.requestAfter(error, responseData, requestData, 'upload', options, raw)
					reject(request.failHandle(err, responseData, requestData, 'upload', options, raw))
				},
				complete: ()=>{
					request.requestComplete(error, responseData, requestData, 'upload', options, raw)
				}
			});

			if(options.onProgressUpdate) {
				task.onProgressUpdate(res => {
					if (res.progress > 0) {
						options.onProgressUpdate(res.progress)
					}
				});
			}
		})
	},

	/**
	 * download
	 */
	download(options={}, arg1) {
		// 适配非对象参数
		if(typeof options === 'string') options = {
			url: options,
			params: arg1,
		}
		let requestData = { header: {}, data: {} }
		let raw
		let responseData
		let error 

		requestData = request.setRequestUrl(requestData, 'download', options)
		requestData = request.setRequestMethod(requestData, 'download', options)
		requestData = request.setRequestHeader(requestData, 'download', options)
		requestData = request.setRequestData(requestData, 'download', options)
		requestData = request.setRequestOther(requestData, 'download', options)
		requestData = request.requestHandle(requestData, 'download', options)
		if(requestData===false) return Promise.reject()
		request.requestBefore(requestData, 'download', options)

		// 请求
		console.log('xrequest download:', requestData)
		return new Promise((resolve, reject)=>{
			const task = uni.downloadFile({
				...requestData,
				success: res=>{
					raw = res
					responseData = res
					console.log('xrequest download response:', responseData)
					request.requestAfter(error, responseData, requestData, 'download', options, raw)

					responseData = request.responseHandle(responseData, requestData, 'download', options, raw)
					if(responseData===false) return reject()

					let code = request.getResponseCode(responseData, requestData, 'download', options, raw)
					let message = request.getResponseMessage(responseData, requestData, 'download', options, raw)
					let data = request.getResponseData(responseData, requestData, 'download', options, raw)
					let ret = request.responseCheck(code, message, data, responseData, requestData, 'download', options, raw)
					console.log('xrequest download response check:', ret)
					responseData = ret.data
					
					if(ret.isClear) uni.$x.auth.logouted(true)
					if(ret.isGoLogin) setTimeout(uni.$x.navigator.goLogin(), 500)
					error = ret.error
					if(error) reject(request.failHandle(error, responseData, requestData, 'upload', options, raw))
					if(!error) resolve(request.successHandle(responseData, requestData, 'download', options, raw))
				},
				fail: err=>{
					request.requestAfter(error, responseData, requestData, 'download', options, raw)
					reject(request.failHandle(err, responseData, requestData, 'download', options, raw))  
				},
				complete: ()=>{
					request.requestComplete(error, responseData, requestData, 'download', options, raw)
				}
			});

			if(options.onProgressUpdate) {
				task.onProgressUpdate(res => {
					if (res.progress > 0) {
						options.onProgressUpdate(res.progress)
					}
				});
			}
		})
	},

	/**
	 * request
	 */
	request(options={notGoLogin: false}, arg1, arg2) {
		// 适配非对象参数
		if(typeof options === 'string') options = {
			url: options,
			data: arg1,
			method: arg2,
			notGoLogin: false, // 首页token失效后不跳转登录
		}
		let requestData = { header: {}, data: {} }
		let raw
		let responseData
		let error 

		requestData = request.setRequestUrl(requestData, 'request', options)
		requestData = request.setRequestMethod(requestData, 'request', options)
		requestData = request.setRequestHeader(requestData, 'request', options)
		requestData = request.setRequestData(requestData, 'request', options)
		requestData = request.setRequestOther(requestData, 'request', options)
		requestData = request.requestHandle(requestData, 'request', options)
		requestData = request.requestHandle(requestData, 'request', options)
		if(requestData===false) return Promise.reject()
		request.requestBefore(requestData, 'request', options)

		// 请求
		console.log('xrequest request:', requestData)
		return uni.request(requestData).then(([err, res])=>{
			raw = res
			responseData = res

			if(err) {
				request.requestAfter(error, responseData, requestData, 'request', options, raw)
				request.failHandle(err, responseData, requestData, 'request', options, raw)
				throw err
			}
			
			console.log('xrequest response:', responseData)
			request.requestAfter(error, responseData, requestData, 'request', options, raw)

			responseData = request.responseHandle(responseData, requestData, 'request', options, raw)
			if(responseData===false) throw ''

			let code = request.getResponseCode(responseData, requestData, 'request', options, raw)
			let message = request.getResponseMessage(responseData, requestData, 'request', options, raw)
			let data = request.getResponseData(responseData, requestData, 'request', options, raw)
			let ret = request.responseCheck(code, message, data, responseData, requestData, 'request', options, raw)
			console.log('xrequest response check:', ret)
			responseData = ret.data

			if(ret.isClear) uni.$x.auth.logouted(true)
			if(ret.isGoLogin) setTimeout(()=>uni.$x.navigator.goLogin(), 500)
			if(ret.error) {
				request.failHandle(ret.error, responseData, requestData, 'request', options, raw)
				throw ret.error
			}else{
				let ret = request.successHandle(responseData, requestData, 'request', options, raw)
				return options.raw?[ret, raw]:ret
			}
		}).finally(()=>{
			request.requestComplete(error, responseData, requestData, 'request', options, raw)
		})
	},
	

	setRequestUrl(req, type, options) {
		let {
			url="", 
			baseUrl=request.urlBase,
			params, 
		} = options
		req.url = baseUrl + url + (params?(url.includes('?')?'&':'?'):'') + (params?(Object.entries(params).filter(([k,v])=>v!==undefined).map(([k,v])=>k+'='+v).join('&')):'')
		return req
	},
	setRequestMethod(req, type, options) {
		let {
			method = type==='upload'?'POST':'GET', 
		} = options
		req.method = method
		return req
	},
	setRequestHeader(req, type, options) {
		let {
			header={}, 
			isAuth=true, 
		} = options;

		Object.assign(req.header, {
			'Accept': 'application/json',
			'Content-Type': 'application/json',
			'type': uni.$x.config.env.type||'',
		}, header)
		if(type==='upload') delete req.header['Content-Type']
		if(isAuth&&uni.$x.auth.getToken()) {
			req.header['Authorization'] = 'Bearer ' + uni.$x.auth.getToken()
			req.header['token'] = 'Bearer ' + uni.$x.auth.getToken()
		}
		return req
	},
	setRequestData(req, type, options) {
		if(type==='upload') {
			req.formData = options.data
			req.name = options.name
			// #ifdef H5
			req.file = options.file
			// #endif
			// #ifndef H5
			req.filePath = options.filePath
			// #endif
			req.files = options.files
		}else{
			req.data = options.data
		}
		return req
	},
	setRequestOther(req, type, options) {
		let {
			timeout=900000,
			dataType,
			responseType
		} = options;
		req.timeout = timeout
		req.dataType = dataType
		req.responseType = responseType
		return req
	},
	requestHandle(req, type, options) {
		if(request.requestHandleHook){
			let ret = request.requestHandleHook(req, type, options)
			if(ret) return ret
		}
		return req
	},
	responseHandle(res, req, type, options) {
		if(request.responseHandleHook){
			let ret = request.responseHandleHook(res, req, type, options)
			if(ret) return ret
		}
		try{
			if(typeof res.data === 'string') res.data = JSON.parse(res.data||'{}')
		}catch(e){
			res.data = []
		}
		return res
	},
	getResponseCode(res, req, type, options, raw) {
		return res.statusCode
	},
	getResponseMessage(res, req, type, options, raw) {
		return type==='download'?res.tempFilePath:(res.data&&(res.data.error||res.data.msg||res.data.message))
	},
	getResponseData(res, req, type, options, raw) {
		return type==='download'?res.tempFilePath:res.data
	},
	responseCheck(code, message, data, res, req, type, options, raw) {
		if(request.responseCheckHook) {
			let hook = request.responseCheckHook(code, message, data, res, req, type, options, raw)
			if(hook) return hook
		}
		if(code === 401&&options.doLogin!==false&&!options.notGoLogin) {
			return {
				error: message||'请重新登录',
				data: res,
				isClear: true,
				isGoLogin: true,
			}
		}else if(code >299) {
			return {
				error: (message==='request:fail'?'':message)||'网络连接失败',
				data: res
			}
		}else{
			return {
				data
			}
		}
	},
	successHandle(res, req, type, options, raw) {
		if(request.responseHandleHook){
			let ret = request.responseHandleHook(res, req, type, options, raw)
			if(ret) return ret
		}
		return res
	},
	failHandle(error, res, req, type, options, raw) {
		console.log('xrequest failHandle:', error)
		if(request.failHandleHook){
			let ret = request.failHandleHook(error, res, req, type, options, raw)
			if(ret) return ret
		}
		let { showError=true } = options
		if(showError) uni.$x.notify.handleException(error)
		return error
	},
	requestBefore(req, type, options) {
		if(request.requestBeforeHook){
			let ret = request.requestBeforeHook(req, type, options)
			if(ret) return ret
		}
		let { loading=true } = options
		if(loading) uni.$x.notify.showLoading()
	},
	requestAfter(error, res, req, type, options) {
		if(request.requestAftereHook){
			let ret = request.requestAfterHook(res, req, type, options)
			if(ret) return ret
		}
		let { loading=true } = options
		if(loading) uni.$x.notify.hideLoading()
	},
	requestComplete(error, res, req, type, options, raw) {
		
	},
}


export default function($x, {
	requestUrlExtend, requestExtend
}={}, app) {
	Object.assign(request, requestExtend||{})
	Object.assign(request.url, requestUrlExtend||{})
	$x.request = request
}
